ident = '$Id: publications.py 119 2006-06-19 18:30:47Z trevor $'

'''The Publication and Issue UI components'''
import sys, wx, rex, common, images, re, base
from xml.sax 	import saxutils
from xml.dom	import minidom

CG_LIST = 100
RB_SUBS = 101
RB_LIST = 102
CB_ARCHIVE=103
ID_PUBLISH=104
ID_OBJECT_PASTE=105
ID_OBJECT_REMOVE=106

class publication( base.editor ):
	def __init__( self, account, pub, treeitem, tree=0 ):
		base.editor.__init__( self, account, pub, treeitem )
		self.parent_tree = tree
		self.load_rex_object()

	def load_rex_object( self ):
		if self.rex_object is None: return
		# Add the standard properties
		cur = wx.BusyCursor()
		try:
			xmlstring = self.rex_object.execute( "get", ID=self.rex_object["id"] )
			self.rex_object.fromxml( xmlstring )
			base.editor.load_rex_object( self )
		except:
			common.show_error( "Failed to load from rex object" )
		del cur

class issue( base.editor ):
	def __init__( self, account, iss, treeitem, tree=0 ):
		base.editor.__init__( self, account, iss, treeitem )
		self.parent_tree = tree
		self.load_rex_object()

	def load_rex_object( self ):
		if self.rex_object is None: return
		# Issues need to be loaded from eas
		if self.account.window: self.account.window.SetStatusText("Loading page..")
		wx.Yield()
		cur = wx.BusyCursor()
		xmlstring = self.rex_object.execute( "get2", ID=self.rex_object["id"] )
		if xmlstring is None:
			raise Exception, "ExecuteError"
		try:
			self.rex_object.fromxml( xmlstring )
			base.editor.load_rex_object( self )
		except:
			common.show_error( "failed to load the issue" )
		del cur
		# Reposition the splitter
		self.vSplitter.SetSashPosition( self.sash_pos )
		if self.account.window: self.account.window.SetStatusText( "Ready" )

	def OnPublish( self, event ):
		dlg = publisher( self, self.account, self.rex_object )
		common.metalic( dlg )
		dlg.Show()
		
class suiPublisherDropTarget( wx.PyDropTarget ):
	def __init__( self, list_object, sui ):
		wx.PyDropTarget.__init__( self )
		self.list 	= list_object
		self.sui	= sui
		self.data   = wx.PyTextDataObject(" ")
		self.SetDataObject( self.data )

	def OnEnter( self, x, y, d ):
		#print "OnEnter: %d %d %d\n" % (x, y, d)
		return wx.DragCopy

	def OnLeave( self ):
		#print "OnLeave"
		pass

	def OnDrop( self, x, y ):
		#print "OnDrop: %d %d\n" % ( x, y )
		return self.list.IsEnabled()

	def OnDragOver( self, x, y, d ):
		#print "OnDragOver: %d %d %d\n" % (x, y, d)
		if self.list.IsEnabled():
			return wx.DragCopy
		else:
			return wx.DragNone

	def OnData( self, x, y, d ):
		#common.dprint ( "OnData: %d %d %d\n" % (x, y, d) )
		if self.GetData():
			data = self.data.GetText()
			common.dprint("Dropped data", data )
			if self.sui.handle_dropped_pasted( data ):
				return wx.DragCopy
		return wx.DragNone

class publisher( wx.Dialog ):
	def __init__( self, parent, account, issue, kind="ISSUES" ):
		title = "Publisher - [ %s ] %s" % ( issue["id"], issue["name"] )
		wx.Dialog.__init__( self, parent, -1, title, wx.DefaultPosition, wx.Size( 350, 400 )  )
		self.objects = {}		# List of objects to publish to
		self.account = account
		self.issue   = issue
		self.current_id = 0
		self.kind	 = kind
		sizer = wx.BoxSizer( wx.VERTICAL )
		sizer.Add( wx.StaticText ( self, -1, "Publish to:" ), 0, wx.LEFT | wx.RIGHT, 20 )
		self.subs = wx.RadioButton( self, RB_SUBS, "Publication subscribers" )
		self.subs.SetValue( 0 )
		sizer.Add( self.subs, 0, wx.LEFT | wx.RIGHT, 20 )
		self.lst  = wx.RadioButton( self, RB_LIST, "Contact and Groups dragged to list below" )
		self.lst.SetValue( 1 )
		sizer.Add( self.lst, 0, wx.LEFT | wx.RIGHT, 20 )
		wx.EVT_RADIOBUTTON( self, RB_SUBS, self.OnUseSubs )
		wx.EVT_RADIOBUTTON( self, RB_LIST, self.OnUseList )
		# The list
		self.list = wx.ListCtrl( self, CG_LIST, style=wx.LC_REPORT )
		self.il = wx.ImageList(16, 16)
		# Load our images
		self.contact_icon 	= self.il.Add( images.getContactBitmap() )
		self.group_icon 	= self.il.Add( images.getGroupBitmap() )
		self.list.SetImageList( self.il, wx.IMAGE_LIST_SMALL )
		sizer.Add( self.list, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 20 )
		info = wx.ListItem()
		info.m_mask = wx.LIST_MASK_TEXT # | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
		#info.m_image = -1
		info.m_format = 0
		info.m_text = "ID"
		self.list.InsertColumnInfo(0, info)
		info.m_text = "Name"
		self.list.InsertColumnInfo(1, info)
		info.m_text = "Kind"
		self.list.InsertColumnInfo(2, info)
		# Set the drop target
		dt = suiPublisherDropTarget( self.list, self )
		self.list.SetDropTarget( dt )
		wx.EVT_RIGHT_DOWN( self.list, self.OnListRightClick )
		# Set the drag and drop events
		#if wx.Platform != '__WXMAC__':
		wx.EVT_LIST_BEGIN_DRAG( self.list, CG_LIST, self.OnBeginDrag )
		self.resize_columns()
		self.use_list = True
		# Add the reply and cc address boxes
		asizer = wx.FlexGridSizer( 2, 2, 3, 3 )
		asizer.AddGrowableCol( 1 )
		self.reply_address = wx.TextCtrl( self, -1 )
		self.cc_address = wx.TextCtrl( self, -1 )
		self.bcc_address = wx.TextCtrl( self, -1 )
		asizer.Add( wx.StaticText( self, -1, "From:" ), 0, wx.EXPAND )
		asizer.Add( self.reply_address, 1, wx.EXPAND )
		asizer.Add( wx.StaticText( self, -1, "CC:" ), 0, wx.EXPAND )
		asizer.Add( self.cc_address, 1, wx.EXPAND )
		asizer.Add( wx.StaticText( self, -1, "BCC:" ), 0, wx.EXPAND )
		asizer.Add( self.bcc_address, 1, wx.EXPAND )
		sizer.Add( asizer, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.NORTH, 20 )
		# Add the archive checkbox
		if kind == "ISSUES":
			self.archive = wx.CheckBox( self, CB_ARCHIVE, "Archive issue" )
			sizer.Add( self.archive, 0, wx.LEFT | wx.RIGHT, 20 )

		# Add the buttons
		self.button_sizer = wx.BoxSizer( wx.HORIZONTAL )
		btn = wx.Button( self, ID_PUBLISH, "&Publish" )
		wx.EVT_BUTTON( self, ID_PUBLISH, self.OnPublish )
		self.button_sizer.Add( (0,0), 0, 1 )
		self.button_sizer.Add( btn, 1, 0 )
		self.button_sizer.Add( (0,0), 0, 1 )
		btn = wx.Button( self, wx.ID_CANCEL, "&Close" )
		btn.SetDefault()
		self.button_sizer.Add( btn, 1, 0 )
		self.button_sizer.Add( (0,0), 0, 1 )

		self.sizer = wx.BoxSizer( wx.VERTICAL )
		self.sizer.Add( sizer, 1, wx.EXPAND | wx.NORTH | wx.SOUTH | wx.EAST | wx.WEST, 10 )
		self.sizer.Add( self.button_sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.SOUTH, 20 )

		self.SetSizer( self.sizer )
		self.SetAutoLayout( 1 )

		menu = wx.Menu()
		menu.Append( ID_OBJECT_PASTE, "&Paste", " Paste contacts or groups from the clipboard." )
		menu.Append( ID_OBJECT_REMOVE, "&Cut", " Remove the selected contacts or groups" )
		self.menu = menu
		wx.EVT_MENU( self, ID_OBJECT_PASTE, self.OnObjectPaste )
		wx.EVT_MENU( self, ID_OBJECT_REMOVE, self.OnObjectRemove )
		# Windows needs this call
		self.Layout()

	def OnListRightClick( self, event ):
		try:
			self.PopupMenu( self.menu, wx.Point( event.m_x + 5, event.m_y + 45) )
		except:
			pass

	def OnObjectPaste( self, event ):
		wx.TheClipboard.Open()
		clipdata = wx.TextDataObject()
		wx.TheClipboard.GetData( clipdata )
		wx.TheClipboard.Close()
		xmlstring = clipdata.GetText()
		self.handle_dropped_pasted( xmlstring )


	def OnObjectRemove( self, event ):
		sel = common.get_selected_in_list( self.list )
		if len( sel ) < 1: return
		for item in sel:
			oid  = self.list.GetItemData( item )
			try:
				self.objects.__delitem__( oid )
				self.list.DeleteItem( item )
			except:
				pass


	def OnUseSubs( self, event ):
		self.list.Enable( False )
		self.use_list = False

	def OnUseList( self, event ):
		self.list.Enable( True )
		self.use_list = True

	def OnPublish( self, event ):
		cur = wx.BusyCursor()
		if not self.use_list:
			to_subscribers = '1'
		else:
			to_subscribers = '0'
		if self.kind == "ISSUES":
			buf = "<publish reply=%s cc=%s bcc=%s issue_id=\"%s\" to_subscribers=\"%s\" >" % \
			( saxutils.quoteattr( self.reply_address.GetValue().strip() ),
			saxutils.quoteattr( self.cc_address.GetValue().strip() ),
			saxutils.quoteattr( self.bcc_address.GetValue().strip() ),
			self.issue["id"], to_subscribers )
		else:
			buf = "<publish reply=%s cc=%s bcc=%s survey_id=\"%s\" to_subscribers=\"%s\" >" % \
			( saxutils.quoteattr( self.reply_address.GetValue().strip() ),
			saxutils.quoteattr( self.cc_address.GetValue().strip() ),
			saxutils.quoteattr( self.bcc_address.GetValue().strip() ),
			self.issue["id"], to_subscribers )
		if self.use_list:
			if ( self.lst.GetValue() ) and not ( self.subs.GetValue() ):
				if len( self.objects ) < 1: return
				for obj in self.objects.values():
					if obj.object_name == "contact":
						tag = "<contact id=%s />" % saxutils.quoteattr( obj["id"] )
					elif obj.object_name == "group":
						tag = "<group id=\"%s\" />" % obj["id"]
					else:
						return
					buf = buf + tag
		cdom = buf + "</publish>"
		result 	= self.account.execute( self.issue.publication.module, "publish", DOM=cdom )
		if result:
			wx.MessageBox( "Your request has been entered and is being processed\nRequest ID: %s" % result,
			"Publishing", wx.OK )
		else:
			# Confirm retry
			wx.MessageBox( "Failed to publish issue, please try again", "Failed to Publish", wx.OK )


	def OnBeginDrag( self, event ):
		list = self.list
		sel = common.get_selected_in_list( list )
		if len( sel ) < 1: return
		oid  = list.GetItemData( sel[0] )

		data = wx.PyTextDataObject(" ")
		ds = wx.DropSource( self )
		ds.SetData( data )
		result = ds.DoDragDrop()
		if result == 5:
			# Remove the object
			try:
				self.objects.__delitem__( oid )
				list.DeleteItem( sel[0] )
			except:
				pass

	def AppendObject( self, object ):
		#~ print "AddpenObject, ", object.object_name
		x = self.list.GetItemCount()
		if object.object_name == "contact":
			icon = self.contact_icon
		elif object.object_name == "group":
			icon = self.group_icon
		else:
			return
		id = object["id"]
		name = object["name"]
		x = self.list.InsertImageStringItem( sys.maxint, id, icon )
		self.list.SetStringItem( x , 1, object["name"] )
		self.list.SetStringItem( x , 2, object.object_name.capitalize() )
		# Add the object to the list of object to publish to
		oid = self.get_new_id()
		self.objects[ oid ] = object
		self.list.SetItemData( x, oid )

	def handle_dropped_pasted( self, data ):
		xmlstring = data.strip()
		#parse the data
		sdom  = None
		snode = None
		try:
			sdom 	= minidom.parseString( xmlstring )
			snode	= sdom.firstChild
		except:
			common.show_error( "Failed to parse pasted data", False )
			del sdom
			del snode
			return False
		if ( snode.nodeName != 'contacts' ) and ( snode.nodeName != 'groups' ): return False
		objs = []
		for inode in snode.getElementsByTagName("contact"):
			con = rex.contacts.contact( self.account, inode.toxml() )
			self.AppendObject( con )
		for inode in snode.getElementsByTagName("group"):
			grp = rex.contacts.group( self.account, inode.toxml() )
			self.AppendObject( grp )
		self.resize_columns()
		return True

	def get_new_id( self ):
		self.current_id = self.current_id + 1
		return self.current_id

	def resize_columns( self ):
		for i in range( self.list.GetColumnCount() ):
			self.list.SetColumnWidth( i, wx.LIST_AUTOSIZE )
